﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Oxage.Midi;

namespace Oxage.Forms
{
	public partial class WindowsMidiForm : UserControl, IConfigPanel
	{
		#region Members
		private SanfordMidiConnector connector;

		//Item for ListBox
		public class MidiOutDevice
		{
			public Interop.MidiOutCaps Device
			{
				get;
				set;
			}

			public int DeviceId
			{
				get;
				set;
			}

			public override string ToString()
			{
				return this.Device.name ?? base.ToString();
			}
		}
		#endregion

		#region Constructors
		public WindowsMidiForm()
		{
			InitializeComponent();
			LoadMidiPorts();
			LoadInstruments();
		}

		public WindowsMidiForm(SanfordMidiConnector connector) : this()
		{
			this.connector = connector;
		}
		#endregion

		#region Properties
		public bool IsLocked
		{
			set
			{
				cmbMidiPort.Enabled = !value;
			}
		}
		#endregion

		#region Methods
		protected void LoadMidiPorts()
		{
			//List output ports
			cmbMidiPort.Items.Clear();
			Interop.MidiOutCaps caps = new Interop.MidiOutCaps();
			for (int c = 0; c < Interop.midiOutGetNumDevs(); c++)
			{
				int result = Interop.midiOutGetDevCaps(c, ref caps, Marshal.SizeOf(caps));
				cmbMidiPort.Items.Add(new MidiOutDevice() { Device = caps, DeviceId = c });
			}
			if (cmbMidiPort.Items.Count > 0)
			{
				cmbMidiPort.SelectedIndex = 0;
			}
		}

		protected void LoadInstruments()
		{
			lstInstruments.Items.Clear();
			IEnumerable<MidiProgram> instruments = MidiProgram.ConvertList(MidiInfo.Instruments);
			foreach (MidiProgram instrument in instruments)
			{
				lstInstruments.Items.Add(instrument);
			}
		}
		#endregion

		#region Event handlers
		private void cmbMidiPort_SelectedIndexChanged(object sender, EventArgs e)
		{
			MidiOutDevice device = cmbMidiPort.SelectedItem as MidiOutDevice;
			if (device != null && this.connector != null && !this.connector.IsOpened)
			{
				this.connector.MidiPort = device.DeviceId;
			}
		}

		private void lstInstruments_SelectedIndexChanged(object sender, EventArgs e)
		{
			MidiProgram program = lstInstruments.SelectedItem as MidiProgram;
			if (program != null && this.connector != null)
			{
				this.connector.ProgramChange(program);
			}
		}
		#endregion

		#region IConfigPanel Members
		public void SetProfile(Profile profile)
		{
			if (profile != null)
			{
				int deviceId = 0;
				int.TryParse(profile["WinMidiPort"], out deviceId);
				foreach (MidiOutDevice device in cmbMidiPort.Items)
				{
					if (device != null && device.DeviceId == deviceId)
					{
						cmbMidiPort.SelectedItem = device;
						break;
					}
				}

				int instrumentIndex = 0;
				int.TryParse(profile["WinMidiInstrument"], out instrumentIndex);
				lstInstruments.SelectedIndex = instrumentIndex;
			}
		}

		public Profile GetProfile()
		{
			Profile profile = new Profile();
			MidiOutDevice device = cmbMidiPort.SelectedItem as MidiOutDevice;
			profile["WinMidiPort"] = (device != null ? device.DeviceId : 0).ToString();
			profile["WinMidiInstrument"] = lstInstruments.SelectedIndex.ToString();
			return profile;
		}

		public UserControl GetUserControl()
		{
			return this;
		}
		#endregion
	}
}
